import type { AppContext } from '../types/index.js';
import { logger } from '../utils/logger.js';
import { config } from '../config/env.js';
import { Encrypt } from '../utils/encrypt.js';
import Router from 'koa-router';
import { SysAdminService } from '../service/system/SysAdmin.js';
import { Response } from '../utils/response.js';
import { IllegalArgumentsException } from '../types/exceptions.js';
import { ValidationUtil } from '../utils/validation.js';
import { SysStatus } from '../enums/system.js';
import { LoginUtil, LoginType, LoginUserType, LoginUserInfo } from '../utils/login-util.js';
import svgCaptcha from 'svg-captcha';

import { redis } from '../utils/redis.js';

const SESSION_CAPPTCHA = 'captcha:key';

/**
 * 创建根路由
 */
const rootRouter = new Router<Record<string, unknown>, AppContext>();

/**
 * 用户登录接口
 */
rootRouter.post('/login', async (ctx: AppContext): Promise<void> => {
  const service = new SysAdminService();
  const clientIp = ctx.ip;
  const { data } = (ctx.request.body || {}) as { data: string };
  // 参数验证
  if (!data) {
    throw new IllegalArgumentsException('参数错误');
  }

  const params = Encrypt.decrypt(data, config.app.secretKey, config.app.secretIv);
  if (!params) {
    throw new IllegalArgumentsException('参数错误');
  }

  const login_request = JSON.parse(params) as unknown as {
    username: string;
    password: string;
    code: string;
    remember: boolean;
  };

  if (!login_request) {
    throw new IllegalArgumentsException('参数错误');
  }

  logger.info('username: %s, password: %s', login_request.username, login_request.password);

  const { username, password, code, remember } = login_request;
  ValidationUtil.validateRequiredString(username, '用户名');
  ValidationUtil.validateRequiredString(password, '密码');

  if (config.app.useCaptcha) {
    ValidationUtil.validateRequiredString(code, '验证码');
  }

  if (await LoginUtil.checkBlackList(username, clientIp)) {
    throw new IllegalArgumentsException('您的IP已被封禁,请稍后再试');
  }

  // 验证码校验
  if (config.app.useCaptcha) {
    const captcha_key = ctx.cookies.get(SESSION_CAPPTCHA);
    if (!captcha_key) {
      throw new IllegalArgumentsException('验证码超时,请重新获取');
    }

    const session_code = await redis.get(captcha_key);
    if (!session_code) {
      throw new IllegalArgumentsException('验证码超时,请重新获取');
    }
    if (code !== session_code) {
      logger.info('code: %s, session_code: %s', code, session_code);
      throw new IllegalArgumentsException('验证码错误');
    }
  }

  const db_admin = await service.loadAdmin(username);

  if (!db_admin || db_admin.status === SysStatus.DISABLE) {
    throw new IllegalArgumentsException('用户不存在或者已被禁用');
  }

  if (Encrypt.encrypt(password) !== db_admin.password) {
    await LoginUtil.loginFail(LoginType.PASSWORD, LoginUserType.ADMIN, username, clientIp);
    throw new IllegalArgumentsException('用户名或密码错误');
  }

  if (config.remember.enabled && remember) {
    const remember_info = Encrypt.encrypt(
      JSON.stringify({
        username: db_admin.admin_name,
        password: Encrypt.decrypt(db_admin.password),
      })
    );

    // 设置自动登录信息到cookie
    ctx.cookies.set(config.remember.cookieKey, remember_info, {
      maxAge: 30 * 24 * 60 * 60 * 1000, //30天
      httpOnly: true,
      signed: true,
    });
  }

  await LoginUtil.loginSuccess(LoginType.PASSWORD, LoginUserType.ADMIN, username, clientIp);

  const loginAdmin: LoginUserInfo = {
    user_id: db_admin.id,
    user_name: db_admin.admin_name,
    user_type: LoginUserType.ADMIN,
  };

  const sessionId = await LoginUtil.createSession(loginAdmin);

  // 设置sessionId到cookie
  ctx.cookies.set(config.auth.session.key, sessionId, {
    maxAge: config.auth.session.maxAge,
    httpOnly: config.auth.session.httpOnly,
    signed: config.auth.session.signed,
  });

  Response.success('登录成功', loginAdmin);
});

/**
 * 获取验证码接口
 */
rootRouter.get('/code', async (ctx: AppContext): Promise<void> => {
  let options = {
    size: 4,
    width: 100,
    height: 50,
    noise: 3,
    color: false,
    mathOperator: '+-',
    background: '#fff',
  };

  const query = ctx.query as Record<string, string>;
  const q_size = parseInt(query.size) || 4;
  const q_width = parseInt(query.width) || 100;
  const q_height = parseInt(query.height) || 50;

  options = Object.assign(options, {
    width: q_width,
    height: q_height,
    size: q_size,
  });

  const captcha = svgCaptcha.createMathExpr(options);

  const sessionId = `${SESSION_CAPPTCHA}:${Date.now()}`;
  // 验证码有效期180秒
  await redis.set(sessionId, captcha.text, 180);
  ctx.cookies.set(SESSION_CAPPTCHA, sessionId, {
    // maxAge: config.auth.session.maxAge,
    httpOnly: config.auth.session.httpOnly,
  });

  ctx.response.type = 'svg';
  ctx.body = captcha.data;
});

export default rootRouter;
